// 从 Gulp 引入输出流(src)、输入流(dest)
// series(串行任务)、parallel(并行任务) 用来组合任务
// watch 用来监听源文件改变
const {
  src,
  dest,
  series,
  parallel,
  watch
} = require('gulp')

const del = require('del')
const browserSync = require('browser-sync')

// 下载 gulp-load-plugins 包，以方便使用各个模块
// 避免对每个模块都写一遍引入操作，从而提高效率
const loadPlugins = require('gulp-load-plugins')

const plugins = loadPlugins()

const bs = browserSync.create();

// 清除插件 del
const clean = () => {
  return del(['dist', '.temp'])
}

// 模板数据
const pageDatas = {
  menus: [{
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [{
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
};


// 处理 sass
const style = () => {
  return src('src/assets/styles/*.scss', {
      base: 'src'
    })
    .pipe(plugins.sass({
      outputStyle: 'expanded'
    }))
    .pipe(dest('.temp'))
}

// 处理 HTML
// 使用了 swig 模板，需要 gulp-swig 插件来转换
const html = () => {
  return src('src/*.html', {
      base: 'src'
    })
    .pipe(plugins.swig({
      data: pageDatas,
      defaults: {
        cache: false
      }
    }))
    .pipe(dest('.temp'))
}

// 处理 JS
// 需要使用到 babel 来转译新语法，所以需要安装 gulp-babel、@babel/core
// 因为 babel 只是一个平台，实际起作用的是其中插件工具，preset 就是一些插件的集合
// preset-env 即是所有最新特性的打包
const script = () => {
  return src('src/assets/scripts/*.js', {
      base: 'src'
    })
    .pipe(plugins.babel({
      presets: ['@babel/preset-env']
    }))
    .pipe(dest('.temp'))
}

// 图象、字体的压缩拷贝
const image = () => {
  return src('src/assets/images/**', {
      base: 'src'
    })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}
const font = () => {
  return src('src/assets/fonts/**', {
      base: 'src'
    })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
};

// public 中的其他资源文件的拷贝
const extra = () => {
  return src('public/**', {
      base: 'public'
    })
    .pipe(dest('dist'))
};

// 通过  gulp-useref 编译依赖文件
// 对 html、js、css 分别压缩
// 压缩前需要用 gulp-if 判断是什么类型的文件
// html 用 gulp-htmlmin 压缩
// js 用 gulp-uglify 压缩
// css 用 gulp-clean-css 压缩
const useref = () => {
  return src('.temp/*.html', {
      base: '.temp'
    }) // 获取所有 html，pipe 到 plugins.useref这个转换流中，useref 会处理其中的构建注释
    .pipe(plugins.useref({
      searchPath: ['.temp', '.'] // searchPath 中指明在什么地方去找构建注释中的文件
    }))
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
}

// 通过 browser-sync 来创建开发服务器
const server = () => {
  // gulp 的 watch， 用于监听源文件的修改
  watch('src/assets/styles/*.scss', style);
  watch('src/assets/scripts/*.js', script);
  watch('src/**/*.html', html);

  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)

  bs.init({
    notify: false,
    port: 1231,
    open: true,
    files: '.temp/**',
    server: {
      // 指明请求资源的位置
      // routes 预先于 baseDir
      // 一个请求发生后，会先在 routes 中看有没得相应的配置
      routes: {
        '/node_modules': 'node_modules'
      },
      baseDir: ['.temp', 'src', 'public']      
    }
  })
}

// 组合编译任务
const compile = parallel(style, html, script)
// 正式构建任务
const build = series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra
  )
)

// 组合编译启动开发服务
const serve = series(compile, server);

module.exports = {
  clean,
  build,
  serve
}
